package com.example.xposed_apk.Utils;

import android.util.Log;
import android.webkit.WebView;

import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.Map;

import okhttp3.Request;
import okhttp3.RequestBody;

import com.android.volley.RequestQueue;

import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;

public class NetWork {

    private static final String TAG = "抓包"; // 统一TAG

    public static void hookAllNetworkLibs(final XC_LoadPackage.LoadPackageParam lpparam) {
        hookOkHttp(lpparam);
        hookRetrofit(lpparam);
        hookWebView(lpparam);
        hookVolley(lpparam);
    }

    // OkHttp3 同步/异步请求拦截
    private static void hookOkHttp(final XC_LoadPackage.LoadPackageParam lpparam) {
        try {
            // 拦截同步请求
            XposedHelpers.findAndHookMethod(
                    "okhttp3.RealCall",
                    lpparam.classLoader,
                    "execute",
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) {
                            interceptOkHttpRequest(param.thisObject);
                        }
                    });

            // 拦截异步请求
            XposedHelpers.findAndHookMethod(
                    "okhttp3.RealCall",
                    lpparam.classLoader,
                    "enqueue",
                    "okhttp3.Callback",
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) {
                            interceptOkHttpRequest(param.thisObject);
                        }
                    });

        } catch (Throwable t) {
            logError("OkHttp拦截失败", t);
        }
    }

    private static void interceptOkHttpRequest(Object call) {
        try {
            Request req = (Request) XposedHelpers.callMethod(call, "request");
            if (req == null) {
                logError("OkHttp请求对象为空", null);
                return;
            }
            String body = extractRequestBody(req.body());
            printLog("OkHttp3",
                    req.method(),
                    req.url().toString(),
                    req.headers().toString(),
                    body);
        } catch (Throwable t) {
            logError("OkHttp请求解析失败", t);
        }
    }

    // Retrofit2 请求拦截
    private static void hookRetrofit(final XC_LoadPackage.LoadPackageParam lpparam) {
        try {
            XposedHelpers.findAndHookMethod(
                    "retrofit2.OkHttpCall",
                    lpparam.classLoader,
                    "request",
                    new XC_MethodHook() {
                        @Override
                        protected void afterHookedMethod(MethodHookParam param) {
                            okhttp3.Request req = (okhttp3.Request) param.getResult();
                            if (req == null) {
                                logError("Retrofit请求对象为空", null);
                                return;
                            }
                            String body = extractRequestBody(req.body());
                            printLog("Retrofit2",
                                    req.method(),
                                    req.url().toString(),
                                    req.headers().toString(),
                                    body);
                        }
                    });
        } catch (Throwable t) {
            logError("Retrofit拦截失败", t);
        }
    }

    // WebView 请求拦截
    private static void hookWebView(final XC_LoadPackage.LoadPackageParam lpparam) {
        try {
            // 拦截GET请求
            XposedHelpers.findAndHookMethod(
                    WebView.class,
                    "loadUrl",
                    String.class,
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) {
                            String url = (String) param.args[0];
                            if (url == null) return;
                            printLog("WebView",
                                    "GET",
                                    url,
                                    "",
                                    null);
                        }
                    });

            // 拦截POST请求
            XposedHelpers.findAndHookMethod(
                    WebView.class,
                    "postUrl",
                    String.class,
                    byte[].class,
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) {
                            String url = (String) param.args[0];
                            byte[] postData = (byte[]) param.args[1];
                            if (url == null || postData == null) return;

                            String body = new String(postData, StandardCharsets.UTF_8);
                            printLog("WebView",
                                    "POST",
                                    url,
                                    "",
                                    body);
                        }
                    });

        } catch (Throwable t) {
            logError("WebView拦截失败", t);
        }
    }

    // Volley 请求拦截
    private static void hookVolley(final XC_LoadPackage.LoadPackageParam lpparam) {
        try {
            XposedHelpers.findAndHookMethod(
                    "com.android.volley.RequestQueue",
                    lpparam.classLoader,
                    "add",
                    com.android.volley.Request.class,
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) {
                            try {
                                com.android.volley.Request<?> req =
                                        (com.android.volley.Request<?>) param.args[0];
                                if (req == null) return;

                                printLog("Volley",
                                        parseVolleyMethod(req),
                                        extractVolleyUrl(req),
                                        extractVolleyHeaders(req),
                                        extractVolleyBody(req));
                            } catch (Throwable t) {
                                logError("Volley请求解析失败", t);
                            }
                        }
                    });
        } catch (Throwable t) {
            logError("Volley拦截失败", t);
        }
    }

    private static String parseVolleyMethod(com.android.volley.Request<?> req) {
        try {
            int method = req.getMethod();
            switch (method) {
                case com.android.volley.Request.Method.GET: return "GET";
                case com.android.volley.Request.Method.POST: return "POST";
                case com.android.volley.Request.Method.PUT: return "PUT";
                case com.android.volley.Request.Method.DELETE: return "DELETE";
                default: return "未知方法";
            }
        } catch (Throwable t) {
            return "方法解析失败";
        }
    }

    private static String extractVolleyUrl(com.android.volley.Request<?> req) {
        try {
            return req.getUrl();
        } catch (Throwable t) {
            return "URL解析失败";
        }
    }

    private static String extractVolleyHeaders(com.android.volley.Request<?> req) {
        try {
            Map<String, String> headers = req.getHeaders();
            return headers != null ? headers.toString() : "无请求头";
        } catch (Throwable t) {
            return "请求头解析失败";
        }
    }

    private static String extractVolleyBody(com.android.volley.Request<?> req) {
        try {
            // 处理Post请求体
            if (req.getBody() != null) {
                return new String(req.getBody(), StandardCharsets.UTF_8);
            }

            // 处理Get请求参数
            if (req.getBody() != null) {
                return req.getBody().toString();
            }

            return "空请求体";
        } catch (Throwable t) {
            return "请求体解析失败: " + t.getMessage();
        }
    }

    // 通用请求体提取方法
    private static String extractRequestBody(Object body) {
        if (body == null) return null;
        try {
            // 兼容不同OkHttp版本
            RequestBody requestBody = (RequestBody) body;
            okio.Buffer buffer = new okio.Buffer();
            requestBody.writeTo(buffer);
            return buffer.readUtf8();
        } catch (Throwable t) {
            return "请求体读取失败: " + t.getMessage();
        }
    }

    // 统一错误日志方法
    private static void logError(String msg, Throwable t) {
        String logMsg = "[" + TAG + "] " + msg;
        if (t != null) {
            logMsg += ": " + Log.getStackTraceString(t);
        }
        XposedBridge.log(logMsg);
    }

    // 日志格式化输出
    private static void printLog(String source, String method, String url,
                                 String headers, String body) {
        StringBuilder log = new StringBuilder()
                .append("\n========== [").append(source).append("] ==========")
                .append("\n请求方法 : ").append(method)
                .append("\n请求地址 : ").append(url);

        if (headers != null && !headers.isEmpty()) {
            log.append("\n请求头:\n").append(headers);
        }
        if (body != null && !body.isEmpty()) {
            log.append("\n请求体:\n").append(body);
        }
        log.append("\n=======================================\n");

        XposedBridge.log("[" + TAG + "]" + log.toString());
    }
}